//! This module provides the [StatefulChunker] and [StatelessChunker] trait and
//! implementations for various algorithms.

pub mod fastcdc;

/// A chunker that keeps its states.
pub trait StatefulChunker {
    /// Chunker-dependant output type (e.g. chunk fingerprint, etc.)
    type Output;

    /// Resume the chunking process on the given buffer.
    /// If a new chunk can be found, return:
    ///
    /// - how many bytes it has consumed before reaching the chunk point
    /// - the chunk size and the chunker-dependant output
    ///
    /// Otherwise `None` is returned.
    fn resume_on(&mut self, buf: &[u8]) -> Option<(usize, (usize, Self::Output))>;

    /// Force a chunk point, can be used when the input has been exhausted but
    /// a chunk point is yet to be declared.
    ///
    /// Return the chunk size and the chunker-dependant output.
    ///
    /// The internal state is reset after this call.
    fn drain(&mut self) -> (usize, Self::Output);

    /// Return `(minimum_chunksize, expected_chunksize, maximum_chunksize)`.
    fn chunksize_options(&self) -> (usize, usize, usize);
}

/// A chunker that doesn't keeps its states, the const parameter `MAX` is the
/// maximum chunk size this chunker can produce.
pub trait StatelessChunker<const MAX: usize> {
    /// Chunker-dependant output type (e.g. chunk fingerprint, etc.)
    type Output;

    /// Find a chunk at the head of the provided buffer, since the length of the
    /// buffer is the maximum chunk size, the chunker is guaranteed to find a
    /// new chunk.
    ///
    /// Returns the chunk size and the chunker-dependant output.
    fn chunk(&mut self, buf: &[u8; MAX]) -> (usize, Self::Output);

    /// Try to find a chunk at the head of the provided buffer, since the length
    /// of the buffer might be smaller than the maximum chunk size, the chunker
    /// might not be able to find a chunk after exhausting the provided buffer.
    ///
    /// If the input buffer is exhausted buf a chunk point is yet to be found, a
    /// chunk point is forced, and we return the (forced) chunker-dependant output,
    /// otherwise we return the chunk size and the chunker-dependant output.
    fn try_chunk(&mut self, buf: &[u8]) -> Result<(usize, Self::Output), Self::Output>;
}
